package org.vacoor.xqq;

import com.google.common.eventbus.Subscribe;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vacoor.nothing.ui.hotkey.OSHotKeyBinder;
import org.vacoor.nothing.ui.hotkey.OSHotKeyManager;
import org.vacoor.nothing.ui.trayicon.AppSysTrayIcon;
import org.vacoor.nothing.ui.trayicon.TrayAnimatedIcon;
import org.vacoor.nothing.ui.util.UIs;
import org.vacoor.nothing.ui.util.WindowMoveHandler;
import org.vacoor.xqq.core.EventBusHolder;
import org.vacoor.xqq.core.bean.*;
import org.vacoor.xqq.core.event.Avatar;
import org.vacoor.xqq.core.event.BuddyStatus;
import org.vacoor.xqq.core.event.Summary;
import org.vacoor.xqq.core.handler.PrintMessageHandler;
import org.vacoor.xqq.core.http.HttpRequestor;
import org.vacoor.xqq.core.http.Request;
import org.vacoor.xqq.core.http.RequestCallbackAdapter;
import org.vacoor.xqq.core.http.Response;
import org.vacoor.xqq.core.mod.BuddyManager;
import org.vacoor.xqq.core.mod.authc.impl.UinPasswordCaptchaStatusToken;
import org.vacoor.xqq.core.mod.authc.impl.WebQQAccessToken;
import org.vacoor.xqq.core.mod.client.impl.WebQQClient;
import org.vacoor.xqq.core.mod.receviver.MessageReceiver;
import org.vacoor.xqq.core.mod.receviver.impl.CaptchaChecker;
import org.vacoor.xqq.core.mod.receviver.impl.SimpleMessageReceiver;
import org.vacoor.xqq.core.poll.impl.DiscuReply;
import org.vacoor.xqq.core.poll.impl.KickReply;
import org.vacoor.xqq.ui.MessageDispatcher;
import org.vacoor.xqq.ui.WindowAutoHide;
import org.vacoor.xqq.ui.chat.UIChatManager2;
import org.vacoor.xqq.ui.comp.tabpane.FlatTabbedPaneUI;
import org.vacoor.xqq.ui.comp.tabpane.QuickOpTabbedPane;
import org.vacoor.xqq.ui.comp.tree.*;

import javax.swing.*;
import javax.swing.tree.DefaultTreeModel;
import javax.swing.tree.MutableTreeNode;
import java.awt.*;
import java.awt.event.*;

//import org.vacoor.xqq.ui.util.AppTrayIcon;

/**
 * User: vacoor
 */
public class Login3 {
    public static final int OS_SHOW_IDENTIFER = OSHotKeyManager.nextIdentifier();
    public static Logger logger = LoggerFactory.getLogger(Login3.class);
    //
    public static final String CHANGE_STATE = "http://d.web2.qq.com/channel/change_status2";
    public static final String SELF_INFO = "http://s.web2.qq.com/api/get_self_info2?ui=1382082183537";

    // http://s.web2.qq.com/api/get_self_info2?ui=1382081032671
    // {"retcode":0,"result":{"birthday":{"month":1,"year":1983,"day":1},"face":525,"phone":"","occupation":"","allow":1,"college":"","uin":2213328508,"blood":0,"constel":0,"lnick":"","vfwebqq":"064de7e8a8bf4873638789e9f124edb6123b6c5bc7308de9801e6ccc219c1ae85307be465eb009ca","homepage":"","vip_info":0,"city":"郑州","country":"中国","personal":"","shengxiao":0,"nick":"HelloWorld","email":"","province":"河南","account":2213328508,"gender":"male","mobile":""}}

    /**
     * 状态修改
     *
     * @param newState
     * @param clientId
     * @param psessionId
     */
    public void changeState(Status newState, String clientId, String psessionId) {
        HttpRequestor.getInstance().send(
                new Request(CHANGE_STATE, Request.HttpMethod.GET)
                        .addHeader("Referer", "http://d.web2.qq.com/proxy.html?v=20130916001&callback=1&id=3")
                        .addParameter("newstatus", newState.getName())
                        .addParameter("clientid", clientId)
                        .addParameter("psessionid", psessionId)
                        .addParameter("ui", Math.random() + ""),

                new RequestCallbackAdapter() {
                    @Override
                    public void onSuccess(Response resp) {
                        logger.debug("修改状态, 响应: {}", resp.getContent().asString());
                    }
                }
        );
    }


    public static void login(String username, char[] password, Status status) throws Exception {
        logger.info("Starting ...");

        final CaptchaChecker checker = new CaptchaChecker(username, String.valueOf(password), status);
        final WebQQClient client = WebQQClient.getCurrentClient();

        // 校验是否需要输入验证码a
        String verify = checker.check();
        if (verify == null) {
            // 获取验证码
            byte[] imgData = checker.getCaptcha();
            verify = (String) JOptionPane.showInputDialog(null, "Please Input Left Captcha", "Captcha", JOptionPane.YES_NO_OPTION, new ImageIcon(imgData), null, null);
            logger.debug("input verify: {}", verify);
        }
        long uin = checker.getUin();
        client.login(new UinPasswordCaptchaStatusToken(uin, password, verify, status));
        logger.debug("登录成功");

        WebQQAccessToken token = (WebQQAccessToken) client.getAccessToken();
        ChatToken chatToken = new ChatToken(token.getUin(), token.getClientId(), token.getPtwebqq(), token.getVfwebqq(), token.getPsessionId());
        logger.debug("login2 result: {}", chatToken);

        final BuddyManager buddyManager = new BuddyManager(chatToken);

        // 获取好友并构建好友树 --------------------
        java.util.List<Category<Buddy>> categories = buddyManager.getBuddies();

        CategoryNode root = new CategoryNode(10000, "root");
        for (Category c : categories) {
            CategoryNode category = new CategoryNode(c);
            root.add(category);
        }

        final AnimatedTree buddiesTree = new AnimatedTree(new DataNodeMonitorTreeModel(root));
        buddiesTree.setUI(new CategoryTreeUI());

        // 讨论组
        CategoryNode discus = new CategoryNode(20000, "讨论组");
        for (Discussion discu : buddyManager.getDiscus()) {
            discus.add(new PeerNode<Discussion>(discu));
        }
        DefaultTreeModel model = new DefaultTreeModel(discus);
        final AnimatedTree discuTree = new AnimatedTree(model);
        discuTree.setUI(new CategoryTreeUI());
        discuTree.setRootVisible(true);

        // 群
        CategoryNode groups = new CategoryNode(30000, "群");
        /*
        for (Group group : buddyManager.getGroups()) {
            // 群消息返回的是 code, 而不是 id, 因此这里使用code
            groups.add(new PeerNode<Group>(group.getCode(), group));
        }
        */
        DefaultTreeModel m = new DefaultTreeModel(groups);
        final AnimatedTree groupTree = new AnimatedTree(m);
        groupTree.setUI(new CategoryTreeUI());
        groupTree.setRootVisible(true);

        // 消息接收器
        final MessageReceiver msgReceiver = new SimpleMessageReceiver(chatToken);
        msgReceiver.start();

        // frame
        UIManager.put("ScrollBar.width", 10);
        JScrollPane scrollPane = new JScrollPane(buddiesTree);
        scrollPane.setBorder(null);
        scrollPane.setViewportBorder(null);
        scrollPane.setBackground(Color.WHITE);

        final JDialog frame = new JDialog();
        frame.setIconImage(new ImageIcon(Login3.class.getClassLoader().getResource("images/logo/qq19x19.png")).getImage());
        frame.setTitle(" X-QQ ");
        frame.getContentPane().setBackground(Color.WHITE);
        frame.setUndecorated(true);

        scrollPane.setHorizontalScrollBarPolicy(ScrollPaneConstants.HORIZONTAL_SCROLLBAR_NEVER);

        final JTabbedPane tabPane = new QuickOpTabbedPane(JTabbedPane.TOP, QuickOpTabbedPane.FILL_TAB_LAYOUT);
        tabPane.setOpaque(true);
        tabPane.setUI(new FlatTabbedPaneUI() {
            @Override
            protected void initDefaults() {
                UIManager.put("TabbedPane.font", UIs.getBestFont());
//                UIManager.put("TabbedPane.tabAreaInsets", new Insets(0, 20, 0, 20)); // 标签区域的 margin
                UIManager.put("TabbedPane.tabAreaInsets", new Insets(0, 0, 0, 0)); // 标签区域的 margin
                UIManager.put("TabbedPane.tabInsets", new Insets(5, 15, 5, 15));  // 标签内容 margin
                UIManager.put("TabbedPane.selectedTabPadInsets", new Insets(0, 0, 0, 0));
                UIManager.put("TabbedPane.contentBorderInsets", new Insets(0, 0, 0, 0));
                UIManager.put("TabbedPane.selectedForeground", new Color(0xE6E7E9));
//                UIManager.put("TabbedPane.background", new Color(0xFCFEFB)); // 背景色
                UIManager.put("TabbedPane.focus", false);
                UIManager.put("TabbedPane.opaque", false);
                UIManager.put("TabbedPane.tabsOpaque", false);
                UIManager.put("TabbedPane.contentOpaque", false);
                UIManager.put("TabbedPane.tabsOverlapBorder", false);
                UIManager.put("TabbedPane.selected", new Color(0x319ACE)); // 选中标签背景色
            }
        });
        tabPane.setBackground(Color.WHITE);

        tabPane.setBorder(BorderFactory.createLineBorder(Color.BLACK, 1));
//        frame.setContentPane(tabPane);
        frame.add(tabPane);
        tabPane.addTab("联系人", scrollPane);
        tabPane.addTab("讨论组", discuTree);
        tabPane.addTab("群", groupTree);
        tabPane.addTab("关于", new JLabel("<html><body><h3>关于</h3><p>擦, Linux 下面为什么没有扣扣</p></body></html>", JLabel.LEFT));

        frame.pack();
        Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
        frame.setLocation(screenSize.width - frame.getWidth() - 50, 50);
        frame.setVisible(true);


        new WindowMoveHandler().bindTo(tabPane);

        try {
            OSHotKeyManager hotKeyManager = OSHotKeyManager.getCurrentOSHotKeyManager();
            if (hotKeyManager == null) {
            }
            OSHotKeyBinder binder = hotKeyManager.getOSHotKeyBinder(OS_SHOW_IDENTIFER);
            // ALT + ESC
//            binder.setHotKey(KeyEvent.ALT_MASK, KeyEvent.VK_ESCAPE);
//            binder.setHotKey(KeyEvent.CTRL_MASK + KeyEvent.ALT_MASK, KeyEvent.VK_H);
            binder.setHotKey(KeyEvent.ALT_MASK, KeyEvent.VK_HOME);

            int showContactIdentifier = OSHotKeyManager.nextIdentifier();
            OSHotKeyBinder buddyTabBinder = hotKeyManager.getOSHotKeyBinder(showContactIdentifier);
        } catch (Throwable e) {
            logger.warn("热键绑定失败: {}", e);
        }


        Object keyLi = new Object() {

            @Subscribe
            public void onKickMeg(KickReply msg) {
                HttpRequestor.getInstance().destory();
                JOptionPane.showMessageDialog(null, "亲, 我被踢出来了, 估计哪个坏蛋在别处登陆了, 在我退出前唯一可以告诉你的就是, 它说:\r\n" + msg.getReason(), "消息", JOptionPane.INFORMATION_MESSAGE);
                System.exit(0);
            }

            @Subscribe
            public void onDiscuMessage(DiscuReply msg) {
//                IdentifiableAndObservableDataNode node = discuTree.getIdentifiableAndObservableNode(msg.getDid());
                discuTree.setShaking(msg.getDid(), true);
            }

            @Subscribe
            public void onAvatar(Avatar msg) {
                final Buddy buddy = buddyManager.getBuddy(msg.getUin());
                if (buddy != null && msg.getBytes() != null) {
                    buddy.setAvatar(new ImageIcon(msg.getBytes()));
                }
            }

            @Subscribe
            public void onLongNick(Summary msg) {
                Buddy buddy = buddyManager.getBuddy(msg.getUin());
                if (buddy != null) {
                    buddy.setSummary(msg.getLnick());
                }
            }

            @Subscribe
            public void onStatusChange(BuddyStatus msg) {
                final Buddy buddy = buddyManager.getBuddy(msg.getUin());
                final Status oldStatus = buddy.getStatus();
                buddy.setClientType(msg.getClientType());
                buddy.setStatus(msg.getStatus());

                MutableTreeNode node = buddiesTree.getIdentifiableAndObservableNode(buddy.getId());
                CategoryNode parent = (CategoryNode) node.getParent();
                if (node.getParent() == null) {
                    return;
                }
                DefaultTreeModel model = (DefaultTreeModel) buddiesTree.getModel();

                if (Status.isInvisible(oldStatus) && !Status.isInvisible(msg.getStatus())) {
                    // 上线将其移动到最前面
                    model.removeNodeFromParent(node);
                    model.insertNodeInto(node, parent, 0);
                } else if (!Status.isInvisible(oldStatus) && Status.isInvisible(msg.getStatus())) {
                    // 下线, 将其移动到后面
                    model.removeNodeFromParent(node);
                    model.insertNodeInto(node, parent, parent.getOnlineCount());
                }
            }
        };

        EventBusHolder.getEventBus().register(keyLi);
        EventBusHolder.getEventBus().register(new PrintMessageHandler());

        // 获取在线好友
        buddyManager.getOnlineBuddies();
//        AppTrayIcon.getTrayIcon();
        frame.addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent e) {
                int ok = JOptionPane.showConfirmDialog(null, "关闭?", "Close", JOptionPane.YES_NO_OPTION, JOptionPane.QUESTION_MESSAGE);
                if ((ok & 1) == 0) {
                    WebQQClient.getCurrentClient().logout();
                    HttpRequestor.getInstance().destory();
                    msgReceiver.shutdown();
                    HttpRequestor.getInstance().destory();
                    TrayAnimatedIcon trayIcon = AppSysTrayIcon.getCurrentAppTrayAnimatedIcon();
                    if (trayIcon != null) {
                        trayIcon.removeToSysTray();
                    }
                    System.exit(0);
                }
            }
        });

        // 构建 树管理
        MessageDispatcher dispatcher = new MessageDispatcher(new UIChatManager2(), buddiesTree, discuTree, groupTree);
        EventBusHolder.getEventBus().register(dispatcher);

        // 托盘
        TrayAnimatedIcon tray = AppSysTrayIcon.addAppTrayAnimatedIcon(new ImageIcon(Login3.class.getClassLoader().getResource("images/logo/logo.png")).getImage(),
                "Java 的系统托盘不敢恭维呀, 不搞了", null
        );
        if (tray == null) {
            logger.warn("创建系统托盘失败");
            return;
        }
        tray.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                frame.setVisible(true);
            }
        });
        new WindowAutoHide(frame).setHideDirection(WindowAutoHide.HIDE_DIRECTION_TOP);

//        Runtime.getRuntime().addShutdownHook(thread); // 添加了之后不知道为什么会死这里
    }
}
